package cn.bqjr.eily.core.aspect;

import cn.bqjr.eily.core.annotation.DisableAutoLog;
import cn.bqjr.eily.core.log.LogAopEntity;
import cn.bqjr.eily.core.log.LogAopUtils;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * 日志自动记录 切面
 */
@Aspect
@Component
public class AutoLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(AutoLogAspect.class);

    @Autowired(required = false)
    private HttpServletRequest request;

    // 切入点 Loggable
    @Pointcut("@annotation(cn.bqjr.eily.core.annotation.AutoLogable)")
    private void logPointCut() {
    }

    @Around("logPointCut()")
    public Object methodExec(ProceedingJoinPoint point) throws Throwable {
        if (isProceed(point)) {
            return point.proceed();
        } else {
            try {
                LogAopEntity entity = LogAopUtils.genarate(point, request);
                beforeExec(entity);
                Object obj = point.proceed();
                afterExec(obj, entity);
                return obj;
            } catch (Exception e) {
                return point.proceed();
            }
        }
    }

    /**
     * 执行前日志记录
     *
     * @param entity
     * @throws Exception
     */
    private void beforeExec(LogAopEntity entity) throws Exception {
        Map<String, Object> reqMap = LogAopUtils.getRequestInfo(entity);
        logger.info("AutoLog before：" + JSON.toJSONString(reqMap));
    }

    /**
     * 执行后日志记录
     *
     * @param returnObj
     * @param entity
     * @throws Exception
     */
    private void afterExec(Object returnObj, LogAopEntity entity) throws Exception {
        Map<String, Object> respMap = LogAopUtils.getResponseInfo(entity, returnObj);
        logger.info("AutoLog after：" + JSON.toJSONString(respMap));
    }

    private boolean isProceed(ProceedingJoinPoint pjp) {
        Class cls = pjp.getTarget().getClass();
        if (cls.isAnnotationPresent(DisableAutoLog.class)) {
            return true;
        } else {
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            Method method = signature.getMethod();
            if ( method.isAnnotationPresent(DisableAutoLog.class)) {
                return true;
            }
        }
        return false;
    }
}
